import { useCallback, useRef, useEffect } from 'react'

// 防抖配置选项
interface DebounceOptions {
  leading?: boolean // 是否立即执行（默认 false）
  trailing?: boolean // 是否延迟执行（默认 true）
}

// 泛型约束：目标函数的参数和返回值类型
type DebounceFn<F extends (...args: any[]) => any> = (
  ...args: Parameters<F>
) => void

/**
 * React 函数组件专用防抖 Hook（无 this 依赖）
 * @param func 需要防抖的目标函数
 * @param delay 延迟时间（毫秒，默认 300ms）
 * @param options 配置项（leading/trailing）
 * @returns 防抖后的函数（自动缓存，避免重复渲染）
 */
function useDebounce<F extends (...args: any[]) => any>(
  func: F,
  delay = 300,
  options: DebounceOptions = {}
): DebounceFn<F> {
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
  const isExecutedRef = useRef(false) // 标记是否已立即执行
  const { leading = false, trailing = true } = options

  // 清理未执行的定时器（组件卸载时触发）
  useEffect(() => {
    return () => {
      if (timerRef.current) {
        clearTimeout(timerRef.current)
        timerRef.current = null
      }
    }
  }, [])

  // 缓存防抖函数（仅当 func/delay/options 变化时重新生成）
  return useCallback<DebounceFn<F>>((...args) => {
    const { leading = false, trailing = true } = options

    // 清除上一次未执行的定时器
    if (timerRef.current) {
      clearTimeout(timerRef.current)
      timerRef.current = null
    }

    // 立即执行逻辑（leading: true）
    if (leading && !isExecutedRef.current) {
      func(...args) // 直接传递参数，无需 this
      isExecutedRef.current = true
    }

    // 延迟执行逻辑（trailing: true）
    if (trailing) {
      timerRef.current = setTimeout(() => {
        // 仅当未立即执行时触发（或 leading 为 false）
        if (!leading || !isExecutedRef.current) {
          func(...args) // 直接传递参数，无需 this
        }
        isExecutedRef.current = false // 重置标记
      }, delay)
    }
  }, [func, delay, leading, trailing]) // 依赖项：func/delay/options 变化时重新生成
}

export default useDebounce
